/*
   Library to facilitate use of the INA226 Voltage, Current & Power monitor
   from Texas Instruments.
   See spec. here: http://www.ti.com/lit/ds/symlink/ina226.pdf.

   Copyright [2018] [AutoFox] autofoxsys@gmail.com

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   This library is for STM32 using HAL provided by CubeMX

   In developing this library, besides reading the INA226 spec, I consulted
   the following code:

   * Linux drivers for the INA family (written in C)
   * https://github.com/SV-Zanshin/INA226 (most useful)

   PLATFORM DEPENDENCE
   Embodied in 3 functions related to I2C reading/writing

	Modified in 11.2020 by Norbert Gal for better portability, some bugs fixed.


*/


#ifndef __INA226_DRIVE_H__
#define __INA226_DRIVE_H__

#include "stm32g0xx_hal.h"
#include "i2c.h"
#include <inttypes.h>
#include <stdbool.h>

//If building a project generated by CubeMX then the I2C handle will
//be defined for you as hi2c1, hi2c2 etc depending on what pins you're using.
//We need to be able to reference this handle here so we define I2C_HANDLE to
//reference it.  You may need to change it depending on what pins you're using.

//Heads up for the classes declared in this header
struct INA226; //This is the one you will use directly
struct INA226_Registers;
struct INA226_HardCodedChipConst;
struct INA226_DefaultSettings;

static const int INA226_I2C_TIMEOUT = 1000;

//Most functions will return an error INA226_status
typedef enum {OK=0, FAIL=-1,
    INA226_TI_ID_MISMATCH = -2,
    INA226_DIE_ID_MISMATCH =-3,
    CONFIG_ERROR = -4,
    I2C_TRANSMISSION_ERROR = -5,
    BAD_PARAMETER = -6,
    NOT_INITIALIZED = -7,
    INVALID_I2C_ADDRESS
}INA226_status;

typedef struct INA226_config{
	void*				hi2c;
	bool     			mInitialized;
    uint8_t  			mI2C_Address;
    uint16_t 			mConfigRegister;        //local copy from the INA226
    uint16_t 			mCalibrationValue;        //local copy from the INA226
    int32_t  			mCurrentMicroAmpsPerBit; //This is the Current_LSB, as defined in the INA266 spec
    int32_t  			mPowerMicroWattPerBit;
} INA226_config;

typedef struct INA226_result{
    int32_t 			ShuntVoltage_uV;        //local copy from the INA226
    int32_t 			BusVoltage_uV;        //local copy from the INA226
    int32_t  			Current_uA; //This is the Current_LSB, as defined in the INA266 spec
    int32_t  			Power_uW;
} INA226_result;

typedef struct INA226{
	INA226_config	Config;
	INA226_result	Result;
}INA226;

//=============================================================================

enum eOperatingMode {//Shutdown=0,
                    ShuntVoltageTriggered        = 1,
                    BusVoltageTriggered          = 2,
                    ShuntAndBusTriggered         = 3,
                    Shutdown                     = 4,
                    ShuntVoltageContinuous       = 5,
                    BusVoltageContinuous         = 6,
                    ShuntAndBusVoltageContinuous = 7}; //default

enum eAlertTrigger {ClearTriggers                = 0x0000, //default
                    ShuntVoltageOverLimit        = 0x8000,
                    ShuntVoltageUnderLimit       = 0x4000,
                    BusVoltageOverLimit          = 0x2000,
                    BusVoltageUnderLimit         = 0x1000,
                    PowerOverLimit               = 0x0800,
                    ConversionReady              = 0x0400};

enum eAlertTriggerCause{
                    Unknown=0,
                    AlertFunctionFlag            = 0x10,
                    ConversionReadyFlag          = 0x08,
                    MathOverflowFlag             = 0x04,
                    AlertPolarityBit             = 0x02};
//=============================================================================

//	Address of INA226 I2C for more info see the INA226 datasheet
#define INA226_ADRESS_0		0b01000000
#define INA226_ADRESS_1		0b01000001
#define INA226_ADRESS_2		0b01000010
#define INA226_ADRESS_3		0b01000011
#define INA226_ADRESS_4		0b01000100
#define INA226_ADRESS_5		0b01000101
#define INA226_ADRESS_6		0b01000110
#define INA226_ADRESS_7		0b01000111
#define INA226_ADRESS_8		0b01001000
#define INA226_ADRESS_9		0b01001001
#define INA226_ADRESS_10	0b01001010
#define INA226_ADRESS_11	0b01001011
#define INA226_ADRESS_12	0b01001100
#define INA226_ADRESS_13	0b01001101
#define INA226_ADRESS_14	0b01001110
#define INA226_ADRESS_15	0b01001111
//=============================================================================

void INA226_Constructor(INA226_config* this, void* i2c_device, uint8_t aI2C_Address);
INA226_status INA226_CheckI2cAddress(INA226_config* this, uint8_t aI2C_Address);

//Resets the INA226 and configures it according to the supplied parameters - should be called first.
//INA226_status INA226_Init(uint8_t aI2C_Address=0x40, double aShuntResistor_Ohms=0.1, double aMaxCurrent_Amps=3.2767);
INA226_status INA226_Init(INA226* this, void* i2c_device, uint8_t aI2C_Address, double aShuntResistor_Ohms, double aMaxCurrent_Amps);

int32_t INA226_GetShuntVoltage_uV(INA226*);
int32_t INA226_GetBusVoltage_uV(INA226*);
int32_t INA226_GetCurrent_uA(INA226*);
int32_t INA226_GetPower_uW(INA226*);
INA226_status INA226_MeasureAll(INA226* this);

INA226_status INA226_SetOperatingMode(INA226_config*,enum eOperatingMode aOpMode);
INA226_status INA226_Hibernate(INA226_config*); //Enters a very low power mode, no voltage measurements
INA226_status INA226_Wakeup(INA226_config*);    //Wake-up and enter the last operating mode

//The trigger value is in microwatts or microvolts, depending on the trigger
INA226_status INA226_ConfigureAlertPinTrigger(INA226_config*,enum eAlertTrigger aAlertTrigger, int32_t aValue, bool aLatching);
//INA226_status INA226_ResetAlertPin(INA226_config*);
INA226_status INA226_ResetAlertPin(INA226_config*,enum  eAlertTriggerCause* aAlertTriggerCause_p ); //provides feedback as to what caused the alert

//The parameters for the two functions below are indices into the tables defined in the INA226 spec
//These tables are copied below for your information (caNumSamplesAveraged & caVoltageConvTimeMicroSecs)
INA226_status INA226_ConfigureVoltageConversionTime(INA226_config*,int aIndexToConversionTimeTable);
INA226_status INA226_ConfigureNumSampleAveraging(INA226_config*,int aIndexToSampleAverageTable);
INA226_status INA226_Debug_GetConfigRegister(INA226_config*,uint16_t* aConfigReg_p);

//Private functions

INA226_status INA226_WriteRegister(INA226_config*,uint8_t aRegister, uint16_t aValue);
INA226_status INA226_ReadRegister(INA226_config*,uint8_t aRegister, uint16_t* aValue_p);
INA226_status INA226_setupCalibration(INA226_config*,double aShuntResistor_Ohms, double aMaxCurrent_Amps);




#endif //__INA226_H__
